{-# LANGUAGE ViewPatterns, DeriveDataTypeable, GeneralizedNewtypeDeriving #-}
----------------------------------------------------------------
--                                                            --
-- Module      :  Data.DataMap                                --
-- License     :  GPL3                                        --
-- Mantainer   :  Mikhail Belyaev                             --
--                                                            --
----------------------------------------------------------------
module Data.DataMap where

import Data.Generics
import qualified Data.Map as M
import Data.Monoid

import Data.Function(on)

-- serializable (with Text.JSON.Generic) version of Data.Map
-- is not very efficient, but works
-- a map implementation with serializing. based on tree map from Data.Map
newtype Map k v = DataMap { unwrapDataMap :: M.Map k v } deriving (Show,Eq,Monoid,Typeable)

wrap = DataMap
unwrap = unwrapDataMap

fromList :: Ord k => [(k,v)] -> Map k v
fromList lst = wrap $ M.fromList lst

toList :: Ord k => Map k v -> [(k,v)]
toList (DataMap m) = M.toList m 

lookup :: Ord k => k -> Map k a -> Maybe a
lookup k (DataMap m) = M.lookup k m

union :: Ord k => Map k a -> Map k a -> Map k a
union (DataMap m0) (DataMap m1) = wrap $ m0 `M.union` m1

size :: Ord k => Map k a -> Int
size = M.size . unwrap

empty :: Ord k => Map k a
empty = wrap M.empty

adjust :: Ord k => (a -> a) -> k -> Map k a -> Map k a
adjust f k (DataMap m) = wrap $ M.adjust f k m

assocs :: Map k a -> [(k, a)]
assocs = M.assocs . unwrap

findMax :: Map k a -> (k, a)
findMax = M.findMax . unwrap

findMin :: Map k a -> (k, a)
findMin = M.findMin . unwrap


multApply :: (a -> a) -> Int -> a -> a
multApply _ 0 x = x
multApply f n x = multApply f (n-1) (f x)


-- here we emulate or type as:
-- data Map k v = VirtualCons { virtualAccessor :: [(k,v)] }
-- that serializes like
-- data Map k v = Data.DataMap { values :: [(k,v)] }
virtualCons :: (Ord k) => [(k,v)] -> Map k v
virtualCons = fromList
virtualAccessor :: (Ord k) => Map k v -> [(k,v)]
virtualAccessor = toList

instance (Data k, Ord k, Data v) => Data (Map k v) where
	 -- gfoldl f z (Cons x0 x1 .. xN) = z Cons `f` x0 `f` x1 .. `f` xN
     gfoldl f z (virtualAccessor -> lst)  = z virtualCons `f` lst
     -- gunfold k z c = case (constIndex c) of
     -- 				     0 -> multApply k cons0Arity (z Cons0)
     -- 				     1 -> multApply k cons1Arity (z Cons1) 
     gunfold k z _ = k (z virtualCons)
     toConstr (DataMap _ ) = con_Map
     dataTypeOf _ = ty_Map
     dataCast2 x = gcast2 x

con_Map = mkConstr ty_Map "Data.DataMap.Map" ["values"] Prefix
ty_Map   = mkDataType "Data.DataMap.Map" [con_Map]